<?php

namespace App\Service\OpenShop;

use AlicFeng\IdentityCard\InfoHelper;
use App\Enums\OpenShop\BaseErrorCode;
use App\Enums\OpenShop\InvestmentPromotion\ErrCode;
use App\Enums\OpenShop\InvestmentPromotion\MainProcessEnum;
use App\Enums\OpenShop\InvestmentPromotion\SignOrderEnum;
use App\Enums\OpenShop\InvestmentPromotion\UserOrderEnum;
use App\Enums\OpenShop\MissionTemplateEnum;
use App\Events\OpenShop\OpenShopProcessEvent;
use App\Events\OpenShop\OrderCreatedEvent;
use App\Exceptions\Custom\CustomHttpResponseException;
use App\Exceptions\Custom\ResponseHttpException;
use App\Http\Resources\OpenShop\InvestmentPromotion\BaseInfoDetailResource;
use App\Http\Resources\OpenShop\InvestmentPromotion\OrderDetailResource;
use App\Http\Resources\OpenShop\InvestmentPromotion\UserExperienceResource;
use App\Http\Resources\OpenShop\InvestmentPromotion\UserIdentityCardResource;
use App\Http\Resources\OpenShop\ShopLocation\PlaceHolderSiteLocationResource;
use App\Models\OpenShop\Common\OpenShopOrderManagerModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopAddressModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderLogModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserBaseInfoModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserContractModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserExperienceModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserIdentityCardModel;
use App\Models\OpenShop\SiteLocation\OpenShopSiteLocationModel;
use App\Models\Recognize\RecognizeBusinessLicenseResult;
use App\Service\BaseService;
use App\Service\OpenShop\Feishu\MainProcessService;
use App\Service\OpenShop\Feishu\MissionTemplateService;
use App\Service\OpenShop\Merchant\OrderEditedEventManager;
use App\Service\OpenShop\SiteLocation\PlaceHolderSiteLocationService;
use App\Support\ChangeSupport;
use Exception;
use Faker\Generator;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Kuafu\File\FileUtil;
use Kuafu\Recognizer\IDCardRecognizer;
use Kuafu\File\PrivateFileUtil;
use Kuafu\Recognizer\RecognizeBusinessLicense;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class UserBaseInfoService extends BaseService
{
    /**
     * @param Object $rmsUser
     * @param array $userIdentityCardInfo
     * @param array $userBaseInfo
     * @param array $userExperience
     * @return array
     */
    public static function insert(
        object $rmsUser,
        array $userIdentityCardInfo,
        array $userBaseInfo,
        array $userExperience,
        array $mainProcessInfo = [],
        array $signOrderInfo = [],
        array $placeholderInfo = []
    ): array {
        try {
            $orderNo = MainProcessService::generateOrderNo();

            DB::beginTransaction();
            $common = [
                "createdAt"    => time(),
                "updatedAt"    => time(),
                "createdByUid" => $rmsUser->id,
                "updatedByUid" => $rmsUser->id
            ];

            $mainProcessInsertData = [
                'step'            => MainProcessEnum::MAIN_PROCESS_INVESTMENT_SIGN,
                'pid'             => 0,
                'orderNo'         => $orderNo,
                'childOrder'      => MainProcessEnum::CHILD_ORDER_0,
                'stepStatusLists' => json_encode(MissionTemplateService::getStepStatusSortLists()),
                'nowStepStatus'   => MissionTemplateEnum::STEP_STATUS_0,
            ];
            $mainProcessInsertData = array_merge($mainProcessInsertData, $mainProcessInfo);

            $mainProcess   = (new OpenShopMainProcessModel($mainProcessInsertData))->addData();
            $mainProcessId = $mainProcess->id;

            $nextCommon                             = array_merge($common, ["orderNo" => $orderNo,]);


            $openShopSignOrderModelInsertData = [
                'mainProcessId'         => $mainProcessId,
                "step"                  => UserOrderEnum::STEP_GENERATE_USER_INFO,
                "investmentManagerId"   => $rmsUser->id,
                "investmentManagerName" => $rmsUser->username,
                "orderNo"               => $orderNo,
            ];
            $openShopSignOrderModelInsertData = array_merge($openShopSignOrderModelInsertData, $signOrderInfo);

            $order = (new OpenShopSignOrderModel($openShopSignOrderModelInsertData))->addData();

            //身份证信息添加
            ChangeSupport::getInstance()->singleInsert(
                new OpenShopUserIdentityCardModel(),
                array_merge($userIdentityCardInfo, $nextCommon),
                "身份信息",
                OpenShopUserIdentityCardModel::$orderLogTranslate,
                collect(array_merge($userIdentityCardInfo, $nextCommon))->keys()->toArray()
            );

            //用户工作经验添加
            ChangeSupport::getInstance()->singleInsert(
                new OpenShopUserExperienceModel(),
                array_merge($userExperience, $nextCommon),
                "工作经验",
                OpenShopUserExperienceModel::getOrderLogTranslate(),
                collect(array_merge($userExperience, $nextCommon))->keys()->toArray()
            );

            //用户基础信息
            ChangeSupport::getInstance()->singleInsert(
                new OpenShopUserBaseInfoModel(),
                array_merge($userBaseInfo, $nextCommon),
                "基础信息",
                OpenShopUserBaseInfoModel::getOrderLogTranslate(),
                collect(array_merge($userBaseInfo, $nextCommon))->except(
                    [
                        "orderNo",
                        "provinceCode",
                        "cityCode",
                        "districtCode",
                        "shopProvinceCode",
                        "shopCityCode",
                        "shopDistrictCode",
                        "chooseShopProvinceCode",
                        "chooseShopCityCode",
                        "chooseShopDistrictCode"
                    ]
                )->keys()->toArray()
            );

            // 同步地址信息
            OpenShopAddressModel::autoAdd($orderNo);

            ChangeSupport::getInstance()->batchChangesWriteToOrderLog(
                $order->id,
                OpenShopSignOrderLogModel::TYPE_ORDER_CREATED,
                $rmsUser->username,
                $rmsUser->id
            );

//            OpenShopUserIdentityCardModel::query()->insert(array_merge($userIdentityCardInfo, $common));
//            OpenShopUserExperienceModel::query()->insert(array_merge($userExperience, $common));
//            OpenShopUserBaseInfoModel::query()->insert(array_merge($userBaseInfo, $nextCommon));

            OpenShopOrderManagerModel::generateManagerOrUpdate(
                OpenShopOrderManagerModel::MANAGER_TYPE_1,
                $mainProcessId,
                $rmsUser->id,
                $rmsUser->username
            );


            DB::commit();


            event(new OrderCreatedEvent($order, $rmsUser->username, $rmsUser->id));
            event(new OpenShopProcessEvent(
                $rmsUser->id,
                $mainProcessId,
                MainProcessEnum::MAIN_PROCESS_INVESTMENT_SIGN,
                MainProcessEnum::INVESTMENT_SIGN_SUBMIT_SIGN_ORDER
            ));
            OrderService::updateOrderPermissionAnchor($orderNo);
            if (!empty($placeholderInfo)) {
                (new PlaceHolderSiteLocationService($orderNo))->manageSavePlaceholder($placeholderInfo);
            }
            return [
                "orderNo"  => $orderNo,
                "userInfo" => [
                    "investmentManagerId"   => $rmsUser->id,
                    "investmentManagerName" => $rmsUser->username
                ]
            ];
        } catch (Exception $e) {
            DB::rollBack();
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(BaseErrorCode::BASE_CODE_INSERT_FAIL),
                $e
            );
        }
    }


    /**
     * @param $uid
     * @param $orderNo
     * @param array $userIdentityCardInfo
     * @param array $userBaseInfo
     * @param array $userExperience
     */
    public static function update(
        $uid,
        $orderNo,
        array $userIdentityCardInfo,
        array $userBaseInfo,
        array $userExperience,
        array $placeholderInfo = []
    ) {
//        $eventManager = new OrderEditedEventManager($orderNo, $uid);
//        $eventManager->recordOriginals();
        try {
            DB::beginTransaction();
            $common = [
                "updatedAt"    => time(),
                "updatedByUid" => $uid
            ];

            $signOrder = OpenShopSignOrderModel::query()->where("orderNo", $orderNo)->first();

//            $identityCardInfo = OpenShopUserIdentityCardModel::getDataByOrderNo($orderNo);
//            unset($userIdentityCardInfo['orderNo']);
//            OpenShopUserIdentityCardModel::query()
//                                         ->where('id', $identityCardInfo->id)
//                                         ->update(array_merge($userIdentityCardInfo, $common));

            $mainSignOrder = OpenShopMainProcessModel::query()->where("orderNo", $orderNo)->first();

            unset($userIdentityCardInfo['orderNo']);
            ChangeSupport::getInstance()->singleUpdate(
                new OpenShopUserIdentityCardModel(),
                function ($query) use ($mainSignOrder) {
                    $query->where('orderNo', $mainSignOrder->orderNo);
                },
                array_merge($userIdentityCardInfo, $common),
                "用户身份信息",
                OpenShopUserIdentityCardModel::$orderLogTranslate
            );

//            $userExperienceInfo = OpenShopUserExperienceModel::getDataByOrderNo($orderNo);
//            unset($userExperience['orderNo']);
//            OpenShopUserExperienceModel::query()
//                                       ->where('id', $userExperienceInfo->id)
//                                       ->update(array_merge($userExperience, $common));
            unset($userExperience['orderNo']);
            ChangeSupport::getInstance()->singleUpdate(
                new OpenShopUserExperienceModel(),
                function ($query) use ($mainSignOrder) {
                    $query->where('orderNo', $mainSignOrder->orderNo);
                },
                array_merge($userExperience, $common),
                "用户工作经验信息",
                OpenShopUserExperienceModel::getOrderLogTranslate()
            );

//            OpenShopUserBaseInfoModel::query()->where('orderNo', $orderNo)->update(array_merge($userBaseInfo, $common));

            ChangeSupport::getInstance()->singleUpdate(
                new OpenShopUserBaseInfoModel(),
                function ($query) use ($orderNo) {
                    $query->where('orderNo', $orderNo);
                },
                array_merge($userBaseInfo, $common),
                "用户身份信息",
                OpenShopUserBaseInfoModel::getOrderLogTranslate(),
                collect(array_merge($userBaseInfo, $common))->except(
                    [
                        "orderNo",
                        "provinceCode",
                        "cityCode",
                        "districtCode",
                        "shopProvinceCode",
                        "shopCityCode",
                        "shopDistrictCode",
                        "chooseShopProvinceCode",
                        "chooseShopCityCode",
                        "chooseShopDistrictCode"
                    ]
                )->keys()->toArray()
            );

            ChangeSupport::getInstance()->batchChangesWriteToOrderLog(
                $signOrder->id,
                OpenShopSignOrderLogModel::TYPE_ORDER_EDITED,
                getRmsUserInfoByAuth()->username,
                getRmsUserInfoByAuth()->id
            );

            // 同步地址信息
            OpenShopAddressModel::autoAdd($orderNo);

            DB::commit();

            if (!empty($placeholderInfo)) {
                // 判断是否已经确认完选址
                if ($signOrder->progressRel->nowStepStatus > MissionTemplateEnum::STEP_STATUS_5) {
                    (new PlaceHolderSiteLocationService($orderNo))->manageSavePlaceholder(['isPlaceholder' => 0], true);
                } else {
                    (new PlaceHolderSiteLocationService($orderNo))->manageSavePlaceholder($placeholderInfo);
                }
            }

        } catch (Exception $e) {
            DB::rollBack();
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(BaseErrorCode::BASE_CODE_UPDATE_FAIL),
                $e
            );
        }
//        $eventManager->recordCurrent();
//        $eventManager->triggerEvent();
    }

    /**
     * 身份证识别
     *
     * @param UploadedFile $uploadedFile
     * @param $type
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function identityCardRecognize(UploadedFile $uploadedFile, $type): array
    {
        try {
            $recognize = new IDCardRecognizer($uploadedFile->getRealPath(), $type);
            $resource  = $recognize->recognize();
            switch ($type) {
                case "face":
                    $idNumber = $resource['Data']['FrontResult']['IDNumber'];
                    $name     = $resource['Data']['FrontResult']['Name'];
                    if (!$idNumber || !$name) {// 身份证未设别到人名或者身份证号提示
                        throw new CustomHttpResponseException(ErrCode::errCodeTrans(ErrCode::CODE_ID_CARD_RECOGNIZE_FAIL));
                    }
                    $resource['Data']['FrontResult'] = array_merge($resource['Data']['FrontResult'], [
                        'star'          => InfoHelper::identityCard()->star($idNumber),
                        'constellation' => InfoHelper::identityCard()->constellation($idNumber),
                        # 获取省
                        'province'      => InfoHelper::identityCard()->province($idNumber, $default = '')
                    ]);
                    break;
                case "back":
                    $resource['Data']['BackResult']['EndDate'] =
                        $resource['Data']['BackResult']['EndDate'] != "长期" ?
                            $resource['Data']['BackResult']['EndDate']
                            : date("Ymd",
                            strtotime($resource['Data']['BackResult']['StartDate']) + 365 * 60 * 60 * 24 * 100);
                    if (!$resource['Data']['BackResult']['EndDate']) {
                        throw new CustomHttpResponseException(ErrCode::errCodeTrans(ErrCode::CODE_ID_CARD_RECOGNIZE_FAIL));
                    }

            }

            $suffix = FileUtil::guessSuffix($uploadedFile->getClientOriginalName());
            return [
                'img'          => PrivateFileUtil::uploadFile(
                    $uploadedFile->getRealPath(),
                    $suffix,
                    generateFileKey() . $suffix
                ),
                'identityCard' => $resource
            ];
        } catch (Exception $e) {
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(ErrCode::CODE_ID_CARD_RECOGNIZE_FAIL),
                $e,
                null,
                [],
                true,
                false
            );
        }
    }

    /**
     * 身份证识别
     *
     * @param UploadedFile $uploadedFile
     * @param $type
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function publicIdentityCardRecognize(UploadedFile $uploadedFile, $type): array
    {
        try {
            $recognize = new IDCardRecognizer($uploadedFile->getRealPath(), $type);
            $resource  = $recognize->recognize();
            switch ($type) {
                case "face":
                    $idNumber                        = $resource['Data']['FrontResult']['IDNumber'];
                    $resource['Data']['FrontResult'] = array_merge($resource['Data']['FrontResult'], [
                        'star'          => InfoHelper::identityCard()->star($idNumber),
                        'constellation' => InfoHelper::identityCard()->constellation($idNumber),
                        # 获取省
                        'province'      => InfoHelper::identityCard()->province($idNumber, $default = '')
                    ]);
                    break;
                case "back":
                    $resource['Data']['BackResult']['EndDate'] =
                        $resource['Data']['BackResult']['EndDate'] != "长期" ?
                            $resource['Data']['BackResult']['EndDate']
                            : date("Ymd",
                            strtotime($resource['Data']['BackResult']['StartDate']) + 365 * 60 * 60 * 24 * 100);

            }

            $suffix = FileUtil::guessSuffix($uploadedFile->getClientOriginalName());
            return [
                'img'          => FileUtil::uploadFile(
                    $uploadedFile->getRealPath(),
                    $suffix,
                    generateFileKey() . $suffix
                ),
                'identityCard' => $resource
            ];
        } catch (Exception $e) {
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(ErrCode::CODE_ID_CARD_RECOGNIZE_FAIL),
                $e,
                null,
                [],
                true,
                false
            );
        }
    }

    /**
     * @param UploadedFile $uploadedFile
     * @param $type
     * @return array
     */

    /**
     * 营业执照识别
     *
     * @param UploadedFile $uploadedFile
     * @param $type
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function businessLicenseRecognize(UploadedFile $uploadedFile, string $expect = ''): array
    {
        try {
            $suffix    = FileUtil::guessSuffix($uploadedFile->getClientOriginalName());
            $arr       = [
                'img'             => FileUtil::uploadFile(
                    $uploadedFile->getRealPath(),
                    $suffix
                ),
                'businessLicense' => []
            ];
            $recognize = new RecognizeBusinessLicense($uploadedFile->getRealPath());
            $resource  = $recognize->recognize();
            $jsonResource = str_replace("'", '', json_encode($resource,JSON_UNESCAPED_UNICODE));
            $resource = json_decode($jsonResource, 1);
            $arr['businessLicense'] = $resource;
            if (isset($arr['img']['path']) && isset($resource['Data'])) {
                RecognizeBusinessLicenseResult::add($arr['img']['path'], $resource['Data']);
            }
            return $arr;
        } catch (Exception $e) {
            if ($expect == 'ignoreOcrError'){
                if (!isset($arr['img'])){
                    self::throwErr('上传失败',BaseErrorCode::BASE_CODE_UPDATE_FAIL);
                }
                return $arr;
            }
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(ErrCode::CODE_BUSINESS_LICENSE_RECOGNIZE_FAIL),
                $e,
                null,
                [],
                true,
                false
            );
        }
    }

    /**
     * @param string $orderNo
     * @return array
     */
    public static function detail(string $orderNo): array
    {
        try {
            $userContract = OpenShopUserContractModel::query()->where("orderNo", $orderNo)->first();
            $placeholder  = new PlaceHolderSiteLocationService($orderNo);

            return [
                "exceptionMsg" => $userContract && $userContract->exceptionMsg,
                'orderDetail'  => OrderDetailResource::collection(OpenShopSignOrderModel::orderDetail($orderNo))
                                                     ->getIterator()->current(),
                'baseInfo'     => BaseInfoDetailResource::collection(
                    [OpenShopUserBaseInfoModel::query()->where('orderNo', $orderNo)->first()]
                )->getIterator()->current(),
                'experience'   => UserExperienceResource::collection(
                    [OpenShopUserExperienceModel::getDataByOrderNo($orderNo)]
                )->getIterator()->current(),
                'identityCard' => UserIdentityCardResource::collection(
                    [OpenShopUserIdentityCardModel::getDataByOrderNo($orderNo)]
                )->getIterator()->current(),
                'placeholder'  => empty($placeholder->getPlaceholderInfo()) ? null :
                    PlaceHolderSiteLocationResource::collection([$placeholder->getPlaceholderInfo()])
                                                   ->getIterator()->current(),
            ];
        } catch (Exception $exception) {
            throw new CustomHttpResponseException(
                ErrCode::errCodeTrans(BaseErrorCode::BASE_CODE_DETAIL_FAIL),
                $exception
            );
        }
    }

    /**
     * @param object $rmsUser
     * @param string $orderNo
     * @param array $baseInfo
     * @param string $remark
     * @throws Exception
     */
    public static function paidOrderBaseInfoUpdate(
        object $rmsUser,
        string $orderNo,
        array $baseInfo,
        string $remark = ""
    ) {
        $eventManager = new OrderEditedEventManager($orderNo, $rmsUser->id);
        $eventManager->recordOriginals();

        try {
            DB::beginTransaction();

            $signOrder = OpenShopSignOrderModel::query()
                                               ->where("orderNo", $orderNo)
                                               ->where("payStatus", ">=", SignOrderEnum::PAY_STATUS_PART)
                                               ->first();

            if (empty($signOrder)) {
                throw new ResponseHttpException(\App\Enums\BaseErrorCode::$ORDER_NOT_SUPPORT_OPERATE);
            }

            $userBaseInfoRes = OpenShopUserBaseInfoModel::query()
                                                        ->where("orderNo", $orderNo)
                                                        ->update(array_merge($baseInfo, [
                                                            "updatedAt"    => time(),
                                                            "updatedByUid" => $rmsUser->id
                                                        ]));

            $userContractRes = OpenShopUserContractModel::query()->where("orderNo", $orderNo)
                                                        ->update([
                                                            "remark"       => trim($remark),
                                                            "updatedAt"    => time(),
                                                            "updatedByUid" => $rmsUser->id
                                                        ]);


            if (!$userBaseInfoRes || !$userContractRes) {
                throw new ResponseHttpException(\App\Enums\BaseErrorCode::$PAID_ORDER_UPDATE_FAIL);
            }

            DB::commit();
        } catch (Exception $exception) {
            DB::rollBack();
            handleException($exception, \App\Enums\BaseErrorCode::$PAID_ORDER_UPDATE_FAIL);
        }

        $eventManager->recordCurrent();
        $eventManager->triggerEvent();
    }
}
